//! Linux accessibility integration using accesskit
//!
//! This module provides the bridge between Azul's accessibility tree
//! and Linux AT-SPI (Assistive Technology Service Provider Interface)
//! via the accesskit_unix library.

use std::sync::{Arc, Mutex};

#[cfg(feature = "a11y")]
use accesskit::{
    Action, ActionHandler, ActionRequest, ActivationHandler, DeactivationHandler,
    Node as AccesskitNode, NodeId as AccesskitNodeId, Role, Tree, TreeUpdate,
};
#[cfg(feature = "a11y")]
use accesskit_unix::Adapter;

/// Linux accessibility adapter that bridges Azul and AT-SPI
#[cfg(feature = "a11y")]
pub struct LinuxAccessibilityAdapter {
    /// accesskit adapter for Linux
    adapter: Arc<Mutex<Option<Adapter>>>,
    /// Pending actions from assistive technology
    pending_actions: Arc<Mutex<Vec<ActionRequest>>>,
}

#[cfg(feature = "a11y")]
impl LinuxAccessibilityAdapter {
    /// Create a new Linux accessibility adapter
    pub fn new() -> Self {
        Self {
            adapter: Arc::new(Mutex::new(None)),
            pending_actions: Arc::new(Mutex::new(Vec::new())),
        }
    }

    /// Initialize the adapter
    ///
    /// This must be called after the window is created to start
    /// the AT-SPI connection.
    pub fn initialize(&mut self, window_name: &str) -> Result<(), String> {
        let pending_actions = Arc::clone(&self.pending_actions);

        // Create handlers
        let activation_handler = AccessibilityActionHandler {
            pending_actions: Arc::clone(&pending_actions),
        };
        let action_handler = AccessibilityActionHandler {
            pending_actions: Arc::clone(&pending_actions),
        };
        let deactivation_handler = AccessibilityDeactivationHandler;

        // Create the accesskit adapter - this sets up the DBus connection
        let adapter = Adapter::new(activation_handler, action_handler, deactivation_handler);

        *self.adapter.lock().unwrap() = Some(adapter);

        Ok(())
    }

    /// Update the accessibility tree
    ///
    /// This should be called after layout when the accessibility tree changes.
    pub fn update_tree(&self, tree_update: TreeUpdate) {
        if let Some(adapter) = self.adapter.lock().unwrap().as_mut() {
            adapter.update_if_active(|| tree_update);
        }
    }

    /// Notify that window focus changed
    pub fn set_focus(&self, _has_focus: bool) {
        // Focus state is automatically managed by the Adapter
        // through AT-SPI protocol, so we don't need to manually update it
    }

    /// Get pending actions from assistive technology
    ///
    /// Returns actions that screen readers or other AT requested,
    /// which should be processed by the application.
    pub fn take_pending_actions(&self) -> Vec<ActionRequest> {
        let mut pending = self.pending_actions.lock().unwrap();
        std::mem::take(&mut *pending)
    }
}

#[cfg(feature = "a11y")]
struct AccessibilityActionHandler {
    pending_actions: Arc<Mutex<Vec<ActionRequest>>>,
}

#[cfg(feature = "a11y")]
impl ActivationHandler for AccessibilityActionHandler {
    fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
        // Return None - initial tree will be set after first layout
        None
    }
}

#[cfg(feature = "a11y")]
impl ActionHandler for AccessibilityActionHandler {
    fn do_action(&mut self, request: ActionRequest) {
        // Queue the action for processing by the main event loop
        self.pending_actions.lock().unwrap().push(request);
    }
}

#[cfg(feature = "a11y")]
struct AccessibilityDeactivationHandler;

#[cfg(feature = "a11y")]
impl DeactivationHandler for AccessibilityDeactivationHandler {
    fn deactivate_accessibility(&mut self) {
        // Called when accessibility is deactivated
        // No cleanup needed for now
    }
}

/// Stub implementation when accessibility feature is disabled
#[cfg(not(feature = "a11y"))]
pub struct LinuxAccessibilityAdapter;

#[cfg(not(feature = "a11y"))]
impl LinuxAccessibilityAdapter {
    pub fn new() -> Self {
        Self
    }

    pub fn initialize(&mut self, _window_name: &str) -> Result<(), String> {
        Ok(())
    }

    pub fn update_tree(&self, _tree_update: ()) {}

    pub fn set_focus(&self, _has_focus: bool) {}

    pub fn take_pending_actions(&self) -> Vec<()> {
        Vec::new()
    }
}
